package com.weixing.mall.provider.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gexin.fastjson.JSON;
import com.google.common.collect.Lists;
import com.weixing.mall.base.exception.BusinessException;
import com.weixing.mall.base.exception.OptimisticLockException;
import com.weixing.mall.base.wrapper.Result;
import com.weixing.mall.core.annotation.OptimisticLockReTry;
import com.weixing.mall.core.enums.SortOrderEnum;
import com.weixing.mall.provider.api.model.vo.ActivityProductVo;
import com.weixing.mall.provider.api.model.vo.FrontGoodsVo;
import com.weixing.mall.provider.api.model.vo.OrderItemVo;
import com.weixing.mall.provider.api.service.GoodsFeign;
import com.weixing.mall.provider.api.service.OrderServiceRpc;
import com.weixing.mall.provider.mapper.ActivityGoodsMapper;
import com.weixing.mall.provider.mapper.ActivityMapper;
import com.weixing.mall.provider.mapper.ProductStockTmpMapper;
import com.weixing.mall.provider.model.domain.Activity;
import com.weixing.mall.provider.model.domain.ActivityGoods;
import com.weixing.mall.provider.model.dto.act.ActivityProductDto;
import com.weixing.mall.provider.model.enums.WhetherEnum;
import com.weixing.mall.provider.model.enums.act.AgentGoodsTypeEnum;
import com.weixing.mall.provider.model.enums.act.UpOrDownEnum;
import com.weixing.mall.provider.model.query.act.ActGoodsQuery;
import com.weixing.mall.provider.model.vo.act.ActivityGoodsVo;
import com.weixing.mall.provider.model.vo.act.ProductStockTmpVo;
import com.weixing.mall.provider.service.IActivityGoodsService;
import com.weixing.mall.provider.support.mq.OrderDivStockRedissonQueueProducer;
import com.weixing.mall.redis.RedisKeyConst;
import com.weixing.mall.redis.order.OrderDivStock;
import com.weixing.mall.redis.order.OrderPayEnd;
import com.weixing.mall.util.ListUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 促销模块-活动商品表 服务实现类
 * </p>
 *
 * @author Small
 * @since 2019-11-16
 */
@Service
public class ActivityGoodsServiceImpl extends ServiceImpl<ActivityGoodsMapper, ActivityGoods> implements IActivityGoodsService {

    @Autowired
    private GoodsFeign goodsFeign;

    @Autowired
    private ProductStockTmpMapper productStockTmpMapper;

    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private IActivityGoodsService activityGoodsService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderServiceRpc orderServiceRpc;

    @Autowired
    private OrderDivStockRedissonQueueProducer orderDivStockRedissonQueueProducer;

    @Override
    public IPage<ActivityGoodsVo> findList(ActGoodsQuery query, Page initMpPage) {
        return baseMapper.findList(initMpPage, query);
    }
    @Override
    public Long findListTotalNum(ActGoodsQuery query) {
        return baseMapper.findListTotalNum(query);
    }


    @Override
    public void addGoods(Activity activity, List<ActivityProductDto> products) {
        if (products.size() > 0) {
            // 查询活动
            ActivityGoods activityGoods = null;
            for (ActivityProductDto product : products) {
                ActivityGoods db = baseMapper.findByActIdAndProductSn(activity.getId(), product.getProductSn());
                if (null == db) {
                    activityGoods = new ActivityGoods();
                    activityGoods.setActId(activity.getId());
                    activityGoods.setActType(activity.getActType().toString());
                    BigDecimal actPrice = activity.getDiscount().multiply(product.getProductPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    activityGoods.setActPrice(actPrice);
                    BeanUtils.copyProperties(product, activityGoods);
                    baseMapper.insert(activityGoods);
                } else {
                    db.setProductCount(product.getProductCount() + db.getProductCount());
                    updateById(db);
                }
            }
        }
    }

    /*对商品进行排序*/
    @Override
    public void sortOrder(ActGoodsQuery entity) {
        int type = entity.getSortOrderEnum().getValue();
        List<ActivityGoods> tmp = baseMapper.findByActId(entity.getActId());
        if (type == SortOrderEnum.SORT_RANDOM.getValue()) {//随机排序
            randomSort(tmp);
        } else if (type == SortOrderEnum.SORT_GOODS.getValue()) {//按照商品的发布时间
            Collections.sort(tmp, Comparator.comparing(ActivityGoods::getGoodsCreatedTime).reversed());
            toUpdate(tmp);
        } else if (type == SortOrderEnum.SORT_STOCK.getValue()) {//按照库存
            Collections.sort(tmp, Comparator.comparing(ActivityGoods::getProductCount).reversed());
            toUpdate(tmp);
        } else if (type == SortOrderEnum.SORT_CLASS.getValue()) {//按照分类排序
            Collections.sort(tmp, Comparator.comparing(ActivityGoods::getGoodsId).reversed());
            toUpdate(tmp);
        }
    }

    private void randomSort(List<ActivityGoods> tmp) {
        List<ActivityGoods> batchUpdateList = new ArrayList<>();
        for (ActivityGoods entity : tmp) {
            ActivityGoods forUpdate = new ActivityGoods();
            forUpdate.setId(entity.getId());
            forUpdate.setOrderNo((long) (Math.random() * 10000));
            batchUpdateList.add(forUpdate);
            /*entity.setOrderNo((long) (Math.random() * 10000));
            baseMapper.updateById(entity);*/
        }
        if (batchUpdateList.size()>0) {
            updateBatchById(batchUpdateList);
        }
    }

    private void toUpdate(List<ActivityGoods> tmp) {
        List<ActivityGoods> batchUpdateList = new ArrayList<>();
        for (int i = 0; i < tmp.size(); i++) {
            ActivityGoods entity = tmp.get(i);
            ActivityGoods forUpdate = new ActivityGoods();
            forUpdate.setId(entity.getId());
            forUpdate.setOrderNo((long) i * 100);
            batchUpdateList.add(forUpdate);
            /*entity.setOrderNo((long) i * 100);
            baseMapper.updateById(entity);*/
        }
        if (batchUpdateList.size()>0) {
            updateBatchById(batchUpdateList);
        }
    }


    @Override
    public HashMap<String, Object> agentGoods(Page initMpPage) {
        HashMap<String, Object> map = new HashMap<>();
        IPage iPage = baseMapper.agentGoods(initMpPage);
        List<FrontGoodsVo> agentGoods = baseMapper.agentGoods();
        List<FrontGoodsVo> agentFrontGoods = baseMapper.agentFrontGoods();
        if (iPage.getRecords().size() == 10) {
            iPage.setTotal(agentGoods.size() + agentFrontGoods.size());
            map.put("record", iPage);
            map.put("type", AgentGoodsTypeEnum.ACT_AGENT);
            return map;
        } else {
            IPage iPage1 = baseMapper.agentFrontGoods(initMpPage);
            List<FrontGoodsVo> records = iPage1.getRecords();
            for (FrontGoodsVo record : records) {
                Result<String> stringResult = goodsFeign.byGoodsIdImg(Math.toIntExact(record.getId()));
                record.setGoodsImg(stringResult.getData());
            }
            iPage1.setTotal(agentGoods.size() + agentFrontGoods.size());
            map.put("record", iPage1);
            map.put("type", AgentGoodsTypeEnum.ACT_SECKILL);
            return map;
        }
    }

    @Override
    public void upOrDown(long[] ids, int flag) {
        baseMapper.upOrDown(ids, flag);
    }

    @Override
    public void addByWholeDepot(Long deptId, Long actId) {
        List<ProductStockTmpVo> tt = productStockTmpMapper.selectByDepotId(deptId);
        saveBat(tt, actId);
    }

    @Override
    public void addByIds(Long[] ids, Long actId) {
        List<ProductStockTmpVo> tt = productStockTmpMapper.selectByIds(ids);
        saveBat(tt, actId);
    }

    @Override
    public ActivityGoods findByActIdAndItemId(Long actId, Long itemId) {
        return baseMapper.findByActIdAndItemId(actId, itemId);
    }

    @Override
    public List<ActivityGoods> findByActId(Long actId) {
        QueryWrapper<ActivityGoods> wrapper = new QueryWrapper<>();
        wrapper.eq("act_id", actId)
                //.eq("up_down", WhetherEnum.YES.getValue());
                .eq("up_down", UpOrDownEnum.UP.getValue());
        return list(wrapper);
    }

    @Override
    @OptimisticLockReTry
    public void divideStock(Long actId, Long id, Integer cnt) {
//        System.out.println("减库存操作   actId: " + actId + ", id : " + id);
        // 执行源方法
        ActivityGoods activityGoods = findByActIdAndItemId(actId, id);
        if (null != activityGoods){
            Integer orgCnt = activityGoods.getProductCount();
            int cntnew = activityGoods.getProductCount() - cnt;
            activityGoods.setProductCount(cntnew > 0  ? cntnew : 0);
            // 如果库存为0则直接下架该商品
            if (activityGoods.getProductCount().intValue() < 1) {
                // activityGoods.setUpDown(WhetherEnum.NO.getValue());
                activityGoods.setUpDown(UpOrDownEnum.DOWM.getValue());
            }else{
                if (orgCnt.intValue() < 1){
                    // activityGoods.setUpDown(com.weixing.mall.base.enums.WhetherEnum.YES.getValue());
                    activityGoods.setUpDown(UpOrDownEnum.UP.getValue());
                }
            }
//            System.out.println("商品数量：" + activityGoods.getProductCount());
            boolean b = updateById(activityGoods);
            if (!b) {
                throw new OptimisticLockException("更新失败");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void offLoading(long actId, long itemId) {
        ActivityGoods byId = findByActIdAndItemId(actId, itemId);
        //byId.setUpDown(WhetherEnum.YES.getValue());
        byId.setUpDown(UpOrDownEnum.UP.getValue());
        updateById(byId);
    }

    @Override
    public void refreshStockInRedis(Long id) {
        ActivityGoods goods = getById(id);
        String key = StrUtil.format(RedisKeyConst.ACT_ITEM_STOCK, goods.getActId(), goods.getProductId());
        redisTemplate.opsForValue().set(key, goods.getProductCount());
    }

    /*
     * 批量导入excel表格活动
     * */
    @Override
    public void importActGoods(List<ActivityProductVo> listResult, Long actId) throws Exception {
        Activity activity = activityMapper.selectById(actId);
        List<ActivityGoods> savelist = Lists.newArrayList();
        List<ActivityGoods> updatelist = Lists.newArrayList();
        for (ActivityProductVo activityProductVo : listResult) {
            ActivityGoods goods = new ActivityGoods();
            BeanUtils.copyProperties(activityProductVo, goods);
            goods.setActId(actId);
            goods.setActType(activity.getActType().toString());
            goods.setProductName(activityProductVo.getGoodsName());
            goods.setProductPrice(new BigDecimal(activityProductVo.getMarketPrice()));
            // 参考元逻辑，没有取小数点
            // goods.setActPrice(new BigDecimal(activityProductVo.getMarketPrice()).multiply(activity.getDiscount()).setScale(0));
            //新定义actprice价格计算  取discountPrice * discout   商品折扣价（零售价） 乘以 活动折扣
            goods.setActPrice(new BigDecimal(activityProductVo.getDiscountPrice()).multiply(activity.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP));
            goods.setUpDown(UpOrDownEnum.UP.getValue());
            goods.setProductCount(activityProductVo.getProductStock());
            goods.setVersion(0);
            goods.setActType(activity.getActType().toString());
            //如果该货品在该活动存在，则将现有的库存转化为已有库存
            coverGoods(savelist, updatelist, goods, actId);
        }
        if (savelist != null && savelist.size() > 0) {
            activityGoodsService.saveBatch(savelist, ListUtil.SIZE);
        }
        if (updatelist != null && updatelist.size() > 0) {
            activityGoodsService.updateBatchById(updatelist,ListUtil.SIZE);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(OrderPayEnd payEnd) {
        Long orderId = payEnd.getOrderId();
        Long itemId = payEnd.getItemId();
        Result<OrderItemVo> orderItemVoResult = orderServiceRpc.selectById(orderId);
        if (!orderItemVoResult.isSuccess()) {
            log.warn("订单服务不可用:" + JSON.toJSONString(orderItemVoResult));
//            throw new BusinessException("订单服务不可用");
        } else {
            OrderItemVo data = orderItemVoResult.getData();
            Long actId = data.getActId();
            Integer isPay = data.getIsPay();
            if (com.weixing.mall.base.enums.WhetherEnum.NO.getValue().equals(isPay)) {
                if (null != actId) {
                    // redis库存+1
                    String rediskey = StrUtil.format(RedisKeyConst.ACT_ITEM_STOCK, actId, itemId);
                    redisTemplate.opsForValue().increment(rediskey, 1);
                    // 数据库库存 + 1
                    orderDivStockRedissonQueueProducer.producer(new OrderDivStock(data.getId(), itemId, actId, -1));
                    // 订单取消
                    Result result = orderServiceRpc.cancelOrder(orderId);
                }
            }
        }
    }

    @Override
    public void upQuery(ActGoodsQuery query) {
        List<ActivityGoodsVo> activityGoodsVoList=baseMapper.findList(query);
        for(ActivityGoodsVo activityGoodsVo:activityGoodsVoList){
            ActivityGoods activityGoods=new ActivityGoods();
            activityGoods.setUpDown(UpOrDownEnum.UP.getValue());
            activityGoods.setId(activityGoodsVo.getId());
            updateById(activityGoods);
        }
    }

    @Override
    public void downQuery(ActGoodsQuery query) {
        List<ActivityGoodsVo> activityGoodsVoList=baseMapper.findList(query);
        for(ActivityGoodsVo activityGoodsVo:activityGoodsVoList){
            ActivityGoods activityGoods=new ActivityGoods();
            activityGoods.setUpDown(UpOrDownEnum.DOWM.getValue());
            activityGoods.setId(activityGoodsVo.getId());
            updateById(activityGoods);
        }
    }

    private void coverGoods(List<ActivityGoods> savelist, List<ActivityGoods> updatelist, ActivityGoods goods, Long actId) {
        ActivityGoods activityGoods = activityGoodsService.getOne(new QueryWrapper<ActivityGoods>().eq("product_id", goods.getProductId()).eq("act_id", actId).last("LIMIT 1"));
        if (activityGoods != null) {
            activityGoods.setProductCount(activityGoods.getProductCount() + goods.getProductCount());
            updatelist.add(activityGoods);
        } else {
            savelist.add(goods);
        }
    }

    private void saveBat(List<ProductStockTmpVo> tt, Long actId) {
        Activity activity = activityMapper.selectById(actId);
        List<ActivityGoods> goods = new ArrayList<ActivityGoods>();
        for (ProductStockTmpVo vo : tt) {
            ActivityGoods entity = new ActivityGoods();
            BeanUtils.copyProperties(vo, entity);
            entity.setId(null);
            entity.setProductCount(vo.getEnableStock());
            entity.setProductFrom(vo.getDepotId().intValue());
            entity.setProductPrice(vo.getMarketPrice());
            if (vo.getMarketPrice() == null || activity.getDiscount() == null) {
                try {
                    throw new Exception("价格存在问题，请核查！");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            //entity.setActPrice(vo.getMarketPrice().multiply(activity.getDiscount()).setScale(0));
            //新定义actprice价格计算  取discountPrice * discout   商品折扣价（零售价） 乘以 活动折扣
            entity.setActPrice(vo.getDiscountPrice().multiply(activity.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP));
            entity.setOrderNo(Long.valueOf((int) (Math.random() * 1000) + ""));
            entity.setUpDown(0);
            entity.setActId(actId);
            entity.setActType(activity.getActType().toString());
            goods.add(entity);

        }
        saveBatch(goods,ListUtil.SIZE);
    }


}
